home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / daemons / syslog_f.z / syslog_f / syslogd / RCS / syslogd.c,v < prev    next >
Encoding:
Text File  |  1993-03-17  |  28.3 KB  |  1,307 lines

  1. head    1.2;
  2. access;
  3. symbols;
  4. locks; strict;
  5. comment    @ * @;
  6.  
  7.  
  8. 1.2
  9. date    93.03.17.19.53.32;    author negaard;    state Exp;
  10. branches;
  11. next    1.1;
  12.  
  13. 1.1
  14. date    93.03.17.19.51.01;    author negaard;    state Exp;
  15. branches;
  16. next    ;
  17.  
  18.  
  19. desc
  20. @Syslog daemon.
  21. @
  22.  
  23.  
  24. 1.2
  25. log
  26. @Implement the local communication method as a named pipe
  27. controlled by the preprocessor variable SYSLOG_USE_FIFO.
  28. POSIX-ification also.
  29. @
  30. text
  31. @/*
  32.  * Copyright (c) 1983, 1988 Regents of the University of California.
  33.  * All rights reserved.
  34.  *
  35.  * Redistribution and use in source and binary forms, with or without
  36.  * modification, are permitted provided that the following conditions
  37.  * are met:
  38.  * 1. Redistributions of source code must retain the above copyright
  39.  *    notice, this list of conditions and the following disclaimer.
  40.  * 2. Redistributions in binary form must reproduce the above copyright
  41.  *    notice, this list of conditions and the following disclaimer in the
  42.  *    documentation and/or other materials provided with the distribution.
  43.  * 3. All advertising materials mentioning features or use of this software
  44.  *    must display the following acknowledgement:
  45.  *    This product includes software developed by the University of
  46.  *    California, Berkeley and its contributors.
  47.  * 4. Neither the name of the University nor the names of its contributors
  48.  *    may be used to endorse or promote products derived from this software
  49.  *    without specific prior written permission.
  50.  *
  51.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  52.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  53.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  54.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  55.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  56.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  57.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  58.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  59.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  60.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  61.  * SUCH DAMAGE.
  62.  */
  63.  
  64. #ifndef lint
  65. char copyright[] =
  66. "@@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
  67.  All rights reserved.\n";
  68. #endif /* not lint */
  69.  
  70. #ifndef lint
  71. static char sccsid[] = "@@(#)syslogd.c    5.45 (Berkeley) 3/2/91";
  72. #endif /* not lint */
  73.  
  74. /*
  75.  *  syslogd -- log system messages
  76.  *
  77.  * This program implements a system log. It takes a series of lines.
  78.  * Each line may have a priority, signified as "<n>" as
  79.  * the first characters of the line.  If this is
  80.  * not present, a default priority is used.
  81.  *
  82.  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  83.  * cause it to reread its configuration file.
  84.  *
  85.  * Defined Constants:
  86.  *
  87.  * MAXLINE -- the maximimum line length that can be handled.
  88.  * DEFUPRI -- the default priority for user messages
  89.  * DEFSPRI -- the default priority for kernel messages
  90.  *
  91.  * Author: Eric Allman
  92.  * extensive changes by Ralph Campbell
  93.  * more extensive changes by Eric Allman (again)
  94.  */
  95.  
  96. #define    MAXLINE        1024        /* maximum line length */
  97. #define    MAXSVLINE    120        /* maximum saved line length */
  98. #define DEFUPRI        (LOG_USER|LOG_NOTICE)
  99. #define DEFSPRI        (LOG_KERN|LOG_CRIT)
  100. #define TIMERINTVL    30        /* interval for checking flush, mark */
  101.  
  102. #include <sys/param.h>
  103. #include <sys/errno.h>
  104. #include <sys/ioctl.h>
  105. #include <sys/stat.h>
  106. #include <sys/wait.h>
  107. #include <sys/socket.h>
  108. #include <sys/file.h>
  109. #ifndef linux
  110. # include <sys/msgbuf.h>
  111. #endif
  112. #include <sys/uio.h>
  113. #include <sys/un.h>
  114. #include <sys/time.h>
  115. #include <sys/resource.h>
  116. #ifdef _POSIX_SOURCE
  117. # include <signal.h>
  118. #else
  119. # include <sys/signal.h>
  120. #endif
  121.  
  122. #include <netinet/in.h>
  123. #include <netdb.h>
  124.  
  125. #include <utmp.h>
  126. #include <setjmp.h>
  127. #include <stdio.h>
  128. #include <ctype.h>
  129. #include <string.h>
  130. #include <unistd.h>
  131. #include "pathnames.h"
  132.  
  133. #ifndef UT_NAMESIZE
  134. # define UT_NAMESIZE 8
  135. #endif
  136.  
  137. #define SYSLOG_NAMES
  138. #include <sys/syslog.h>
  139.  
  140. char    *LogName = _PATH_LOG;
  141. char    *ConfFile = _PATH_LOGCONF;
  142. char    *PidFile = _PATH_LOGPID;
  143. char    ctty[] = _PATH_CONSOLE;
  144.  
  145. #define FDMASK(fd)    (1 << (fd))
  146.  
  147. #define    dprintf        if (Debug) printf
  148.  
  149. #define MAXUNAMES    20    /* maximum number of user names */
  150.  
  151. /*
  152.  * Flags to logmsg().
  153.  */
  154.  
  155. #define IGN_CONS    0x001    /* don't print on console */
  156. #define SYNC_FILE    0x002    /* do fsync on file after printing */
  157. #define ADDDATE        0x004    /* add a date to the message */
  158. #define MARK        0x008    /* this message is a mark */
  159.  
  160. /*
  161.  * This structure represents the files that will have log
  162.  * copies printed.
  163.  */
  164.  
  165. struct filed {
  166.     struct    filed *f_next;        /* next in linked list */
  167.     short    f_type;            /* entry type, see below */
  168.     short    f_file;            /* file descriptor */
  169.     time_t    f_time;            /* time this was last written */
  170.     u_char    f_pmask[LOG_NFACILITIES+1];    /* priority mask */
  171.     union {
  172.         char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
  173.         struct {
  174.             char    f_hname[MAXHOSTNAMELEN+1];
  175.             struct sockaddr_in    f_addr;
  176.         } f_forw;        /* forwarding address */
  177.         char    f_fname[MAXPATHLEN];
  178.     } f_un;
  179.     char    f_prevline[MAXSVLINE];        /* last message logged */
  180.     char    f_lasttime[16];            /* time of last occurrence */
  181.     char    f_prevhost[MAXHOSTNAMELEN+1];    /* host from which recd. */
  182.     int    f_prevpri;            /* pri of f_prevline */
  183.     int    f_prevlen;            /* length of f_prevline */
  184.     int    f_prevcount;            /* repetition cnt of prevline */
  185.     int    f_repeatcount;            /* number of "repeated" msgs */
  186. };
  187.  
  188. /*
  189.  * Intervals at which we flush out "message repeated" messages,
  190.  * in seconds after previous message is logged.  After each flush,
  191.  * we move to the next interval until we reach the largest.
  192.  */
  193. int    repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
  194. #define    MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
  195. #define    REPEATTIME(f)    ((f)->f_time + repeatinterval[(f)->f_repeatcount])
  196. #define    BACKOFF(f)    { if (++(f)->f_repeatcount > MAXREPEAT) \
  197.                  (f)->f_repeatcount = MAXREPEAT; \
  198.             }
  199.  
  200. /* values for f_type */
  201. #define F_UNUSED    0        /* unused entry */
  202. #define F_FILE        1        /* regular file */
  203. #define F_TTY        2        /* terminal */
  204. #define F_CONSOLE    3        /* console terminal */
  205. #define F_FORW        4        /* remote machine */
  206. #define F_USERS        5        /* list of users */
  207. #define F_WALL        6        /* everyone logged on */
  208.  
  209. char    *TypeNames[7] = {
  210.     "UNUSED",    "FILE",        "TTY",        "CONSOLE",
  211.     "FORW",        "USERS",    "WALL"
  212. };
  213.  
  214. struct    filed *Files;
  215. struct    filed consfile;
  216.  
  217. int    Debug;            /* debug flag */
  218. char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
  219. char    *LocalDomain;        /* our local domain name */
  220. int    InetInuse = 0;        /* non-zero if INET sockets are being used */
  221. int    finet;            /* Internet datagram socket */
  222. int    LogPort;        /* port number for INET connections */
  223. int    Initialized = 0;    /* set when we have initialized ourselves */
  224. int    MarkInterval = 20 * 60;    /* interval between marks in seconds */
  225. int    MarkSeq = 0;        /* mark sequence number */
  226.  
  227. extern    int errno;
  228. extern    char *ctime(), *index(), *calloc();
  229.  
  230. main(argc, argv)
  231.     int argc;
  232.     char **argv;
  233. {
  234.     register int i;
  235.     register char *p;
  236.     int funix, inetm, fklog, klogm, len;
  237. #ifndef SYSLOG_USE_FIFO
  238.     struct sockaddr_un sunx;
  239.     struct sockaddf_un fromunix;
  240. #endif /* SYSLOG_USE_FIFO */
  241.     struct sockaddr_in sin, frominet;
  242.     FILE *fp;
  243.     int ch;
  244.     char line[MAXLINE + 1];
  245.     extern int optind;
  246.     extern char *optarg;
  247.     void die(), domark(), init(), reapchild();
  248. #ifdef _POSIX_SOURCE
  249.     struct sigaction act;
  250. #endif
  251.  
  252.     while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
  253.         switch((char)ch) {
  254.         case 'd':        /* debug */
  255.             Debug++;
  256.             break;
  257.         case 'f':        /* configuration file */
  258.             ConfFile = optarg;
  259.             break;
  260.         case 'm':        /* mark interval */
  261.             MarkInterval = atoi(optarg) * 60;
  262.             break;
  263.         case 'p':        /* path */
  264.             LogName = optarg;
  265.             break;
  266.         case '?':
  267.         default:
  268.             usage();
  269.         }
  270.     if (argc -= optind)
  271.         usage();
  272.  
  273.     if (!Debug)
  274.         daemon(0, 0);
  275.     else
  276.         setlinebuf(stdout);
  277.  
  278.     consfile.f_type = F_CONSOLE;
  279.     (void) strcpy(consfile.f_un.f_fname, ctty);
  280.     (void) gethostname(LocalHostName, sizeof LocalHostName);
  281.     if (p = index(LocalHostName, '.')) {
  282.         *p++ = '\0';
  283.         LocalDomain = p;
  284.     }
  285.     else
  286.         LocalDomain = "";
  287. #ifdef _POSIX_SOURCE
  288.     act.sa_handler = die;
  289.     (void) sigemptyset (&act.sa_mask);
  290.     act.sa_flags = 0;
  291.     (void) sigaction (SIGTERM, &act, NULL);
  292.     if (Debug)
  293.         act.sa_handler = SIG_IGN;
  294.     (void) sigaction (SIGINT, &act, NULL);
  295.     (void) sigaction (SIGQUIT, &act, NULL);
  296.     act.sa_handler = reapchild;
  297.     (void) sigaction (SIGCHLD, &act, NULL);
  298.     act.sa_handler = domark;
  299.     (void) sigaction (SIGALRM, &act, NULL);
  300. #else
  301.     (void) signal(SIGTERM, die);
  302.     (void) signal(SIGINT, Debug ? die : SIG_IGN);
  303.     (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
  304.     (void) signal(SIGCHLD, reapchild);
  305.     (void) signal(SIGALRM, domark);
  306. #endif
  307.     (void) alarm(TIMERINTVL);
  308.     (void) unlink(LogName);
  309.  
  310. #ifdef SYSLOG_USE_FIFO
  311.     (void) mkfifo(LogName, 0666);
  312.     /*
  313.      * Open with O_RDWR so the open system call doesn't block.
  314.      * Could use O_RDONLY|O_NONBLOCK, but that causes the
  315.      * select system call to think the fifo is always available
  316.      * for reading (on Linux, at least).
  317.      */
  318.     funix = open(LogName, O_RDWR, 0);
  319. #else
  320.     bzero((char *)&sunx, sizeof(sunx));
  321.     sunx.sun_family = AF_UNIX;
  322.     (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
  323.     funix = socket(AF_UNIX, SOCK_DGRAM, 0);
  324. #endif
  325.     if (funix < 0 ||
  326. #ifndef SYSLOG_USE_FIFO
  327.         bind(funix, (struct sockaddr *) &sunx,
  328. #ifdef linux
  329.          sizeof(sunx.sun_family)+
  330. #else
  331.          sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+
  332. #endif
  333.          strlen(sunx.sun_path)) < 0 ||
  334. #endif /* ! SYSLOG_USE_FIFO */
  335.         chmod(LogName, 0666) < 0) {
  336.         (void) sprintf(line, "cannot create %s", LogName);
  337.         logerror(line);
  338.         dprintf("cannot create %s (%d)\n", LogName, errno);
  339.         die(0);
  340.         }
  341.     finet = socket(AF_INET, SOCK_DGRAM, 0);
  342.     if (finet >= 0) {
  343.         struct servent *sp;
  344.  
  345.         sp = getservbyname("syslog", "udp");
  346.         if (sp == NULL) {
  347.             errno = 0;
  348.             logerror("syslog/udp: unknown service");
  349.             die(0);
  350.         }
  351.         bzero((char *)&sin, sizeof(sin));
  352.         sin.sin_family = AF_INET;
  353.         sin.sin_port = LogPort = sp->s_port;
  354.         if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  355.             logerror("bind");
  356.             if (!Debug)
  357.                 die(0);
  358.         } else {
  359.             inetm = FDMASK(finet);
  360.             InetInuse = 1;
  361.         }
  362.     }
  363.     if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
  364.         klogm = FDMASK(fklog);
  365.     else {
  366.         dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
  367.         klogm = 0;
  368.     }
  369.  
  370.     /* tuck my process id away */
  371.     fp = fopen(PidFile, "w");
  372.     if (fp != NULL) {
  373.         fprintf(fp, "%d\n", getpid());
  374.         (void) fclose(fp);
  375.     }
  376.  
  377.     dprintf("off & running....\n");
  378.  
  379.     init();
  380. #ifdef _POSIX_SOURCE
  381.     act.sa_handler = init;
  382.     (void) sigaction(SIGHUP, &act, NULL);
  383. #else
  384.     (void) signal(SIGHUP, init);
  385. #endif
  386.  
  387.     for (;;) {
  388.         int nfds, readfds = FDMASK(funix) | inetm | klogm;
  389.  
  390.         errno = 0;
  391.         dprintf("readfds = %#x\n", readfds);
  392.         nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
  393.             (fd_set *) NULL, (struct timeval *) NULL);
  394.         if (nfds == 0)
  395.             continue;
  396.         if (nfds < 0) {
  397.             if (errno != EINTR)
  398.                 logerror("select");
  399.             continue;
  400.         }
  401.         dprintf("got a message (%d, %#x)\n", nfds, readfds);
  402.         if (readfds & klogm) {
  403.             i = read(fklog, line, sizeof(line) - 1);
  404.             if (i > 0) {
  405.                 line[i] = '\0';
  406.                 printsys(line);
  407.             } else if (i < 0 && errno != EINTR) {
  408.                 logerror("klog");
  409.                 fklog = -1;
  410.                 klogm = 0;
  411.             }
  412.         }
  413.         if (readfds & FDMASK(funix)) {
  414. #ifdef SYSLOG_USE_FIFO
  415.                 i = read(funix, line, MAXLINE);
  416. #else
  417.             len = sizeof fromunix;
  418.             i = recvfrom(funix, line, MAXLINE, 0,
  419.                 (struct sockaddr *) &fromunix, &len);
  420. #endif /* SYSLOG_USE_FIFO */
  421.             if (i > 0) {
  422.                 line[i] = '\0';
  423.                 printline(LocalHostName, line);
  424.             } else if (i < 0
  425.                    && errno != EINTR
  426. #if defined (SYSLOG_USE_FIFO) && defined (_POSIX_SOURCE)
  427.                    && errno != EAGAIN
  428. #endif
  429.                    )
  430.                 logerror("recv unix");
  431.         }
  432.         if (readfds & inetm) {
  433.             len = sizeof frominet;
  434.             i = recvfrom(finet, line, MAXLINE, 0,
  435.                 (struct sockaddr *) &frominet, &len);
  436.             if (i > 0) {
  437.                 extern char *cvthname();
  438.  
  439.                 line[i] = '\0';
  440.                 printline(cvthname(&frominet), line);
  441.             } else if (i < 0 && errno != EINTR)
  442.                 logerror("recvfrom inet");
  443.         } 
  444.     }
  445. }
  446.  
  447. usage()
  448. {
  449.     (void) fprintf(stderr,
  450.         "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n");
  451.     exit(1);
  452. }
  453.  
  454. /*
  455.  * Take a raw input line, decode the message, and print the message
  456.  * on the appropriate log files.
  457.  */
  458.  
  459. printline(hname, msg)
  460.     char *hname;
  461.     char *msg;
  462. {
  463.     register char *p, *q;
  464.     register int c;
  465.     char line[MAXLINE + 1];
  466.     int pri;
  467.  
  468.     /* test for special codes */
  469.     pri = DEFUPRI;
  470.     p = msg;
  471.     if (*p == '<') {
  472.         pri = 0;
  473.         while (isdigit(*++p))
  474.             pri = 10 * pri + (*p - '0');
  475.         if (*p == '>')
  476.             ++p;
  477.     }
  478.     if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  479.         pri = DEFUPRI;
  480.  
  481.     /* don't allow users to log kernel messages */
  482.     if (LOG_FAC(pri) == LOG_KERN)
  483.         pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
  484.  
  485.     q = line;
  486.  
  487.     while ((c = *p++ & 0177) != '\0' &&
  488.         q < &line[sizeof(line) - 1])
  489.         if (iscntrl(c))
  490.             if (c == '\n')
  491.                 *q++ = ' ';
  492.             else if (c == '\t')
  493.                 *q++ = '\t';
  494.             else {
  495.                 *q++ = '^';
  496.                 *q++ = c ^ 0100;
  497.             }
  498.         else
  499.             *q++ = c;
  500.     *q = '\0';
  501.  
  502.     logmsg(pri, line, hname, 0);
  503. }
  504.  
  505. /*
  506.  * Take a raw input line from /dev/klog, split and format similar to syslog().
  507.  */
  508.  
  509. printsys(msg)
  510.     char *msg;
  511. {
  512.     register char *p, *q;
  513.     register int c;
  514.     char line[MAXLINE + 1];
  515.     int pri, flags;
  516.     char *lp;
  517.  
  518.     (void) strcpy(line, _PATH_UNIX);
  519.     (void) strcat(line, ": ");
  520.     lp = line + strlen(line);
  521.     for (p = msg; *p != '\0'; ) {
  522.         flags = SYNC_FILE | ADDDATE;    /* fsync file after write */
  523.         pri = DEFSPRI;
  524.         if (*p == '<') {
  525.             pri = 0;
  526.             while (isdigit(*++p))
  527.                 pri = 10 * pri + (*p - '0');
  528.             if (*p == '>')
  529.                 ++p;
  530.         } else {
  531.             /* kernel printf's come out on console */
  532.             flags |= IGN_CONS;
  533.         }
  534.         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  535.             pri = DEFSPRI;
  536.         q = lp;
  537.         while (*p != '\0' && (c = *p++) != '\n' &&
  538.             q < &line[MAXLINE])
  539.             *q++ = c;
  540.         *q = '\0';
  541.         logmsg(pri, line, LocalHostName, flags);
  542.     }
  543. }
  544.  
  545. time_t    now;
  546.  
  547. /*
  548.  * Log a message to the appropriate log files, users, etc. based on
  549.  * the priority.
  550.  */
  551.  
  552. logmsg(pri, msg, from, flags)
  553.     int pri;
  554.     char *msg, *from;
  555.     int flags;
  556. {
  557.     register struct filed *f;
  558.     int fac, prilev;
  559. #ifdef _POSIX_SOURCE
  560.     sigset_t bsigs;
  561. #else
  562.     int omask;
  563. #endif
  564.     int msglen;
  565.     char *timestamp;
  566.     time_t time();
  567.  
  568.     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
  569.         pri, flags, from, msg);
  570.  
  571. #ifdef _POSIX_SOURCE
  572.     sigemptyset(&bsigs);
  573.     sigaddset(&bsigs, SIGHUP);
  574.     sigaddset(&bsigs, SIGALRM);
  575.     (void) sigprocmask(SIG_BLOCK, &bsigs, (sigset_t *)NULL);
  576. #else
  577.     omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
  578. #endif
  579.  
  580.     /*
  581.      * Check to see if msg looks non-standard.
  582.      */
  583.     msglen = strlen(msg);
  584.     if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
  585.         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
  586.         flags |= ADDDATE;
  587.  
  588.     (void) time(&now);
  589.     if (flags & ADDDATE)
  590.         timestamp = ctime(&now) + 4;
  591.     else {
  592.         timestamp = msg;
  593.         msg += 16;
  594.         msglen -= 16;
  595.     }
  596.  
  597.     /* extract facility and priority level */
  598.     if (flags & MARK)
  599.         fac = LOG_NFACILITIES;
  600.     else
  601.         fac = LOG_FAC(pri);
  602.     prilev = LOG_PRI(pri);
  603.  
  604.     /* log the message to the particular outputs */
  605.     if (!Initialized) {
  606.         f = &consfile;
  607.         f->f_file = open(ctty, O_WRONLY, 0);
  608.  
  609.         if (f->f_file >= 0) {
  610.             fprintlog(f, flags, msg);
  611.             (void) close(f->f_file);
  612.         }
  613. #ifdef _POSIX_SOURCE
  614.         (void) sigprocmask(SIG_UNBLOCK, &bsigs, (sigset_t *)NULL);
  615. #else
  616.         (void) sigsetmask(omask);
  617. #endif
  618.         return;
  619.     }
  620.     for (f = Files; f; f = f->f_next) {
  621.         /* skip messages that are incorrect priority */
  622.         if (f->f_pmask[fac] < prilev ||
  623.             f->f_pmask[fac] == INTERNAL_NOPRI)
  624.             continue;
  625.  
  626.         if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
  627.             continue;
  628.  
  629.         /* don't output marks to recently written files */
  630.         if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
  631.             continue;
  632.  
  633.         /*
  634.          * suppress duplicate lines to this file
  635.          */
  636.         if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
  637.             !strcmp(msg, f->f_prevline) &&
  638.             !strcmp(from, f->f_prevhost)) {
  639.             (void) strncpy(f->f_lasttime, timestamp, 15);
  640.             f->f_prevcount++;
  641.             dprintf("msg repeated %d times, %ld sec of %d\n",
  642.                 f->f_prevcount, now - f->f_time,
  643.                 repeatinterval[f->f_repeatcount]);
  644.             /*
  645.              * If domark would have logged this by now,
  646.              * flush it now (so we don't hold isolated messages),
  647.              * but back off so we'll flush less often
  648.              * in the future.
  649.              */
  650.             if (now > REPEATTIME(f)) {
  651.                 fprintlog(f, flags, (char *)NULL);
  652.                 BACKOFF(f);
  653.             }
  654.         } else {
  655.             /* new line, save it */
  656.             if (f->f_prevcount)
  657.                 fprintlog(f, 0, (char *)NULL);
  658.             f->f_repeatcount = 0;
  659.             (void) strncpy(f->f_lasttime, timestamp, 15);
  660.             (void) strncpy(f->f_prevhost, from,
  661.                     sizeof(f->f_prevhost));
  662.             if (msglen < MAXSVLINE) {
  663.                 f->f_prevlen = msglen;
  664.                 f->f_prevpri = pri;
  665.                 (void) strcpy(f->f_prevline, msg);
  666.                 fprintlog(f, flags, (char *)NULL);
  667.             } else {
  668.                 f->f_prevline[0] = 0;
  669.                 f->f_prevlen = 0;
  670.                 fprintlog(f, flags, msg);
  671.             }
  672.         }
  673.     }
  674. #ifdef _POSIX_SOURCE
  675.     (void) sigprocmask(SIG_UNBLOCK, &bsigs, (sigset_t *)NULL);
  676. #else
  677.     (void) sigsetmask(omask);
  678. #endif
  679. }
  680.  
  681. fprintlog(f, flags, msg)
  682.     register struct filed *f;
  683.     int flags;
  684.     char *msg;
  685. {
  686.     struct iovec iov[6];
  687.     register struct iovec *v;
  688.     register int l;
  689.     char line[MAXLINE + 1], repbuf[80], greetings[200];
  690.  
  691.     v = iov;
  692.     if (f->f_type == F_WALL) {
  693.         v->iov_base = greetings;
  694.         v->iov_len = sprintf(greetings,
  695.             "\r\n\7Message from syslogd@@%s at %.24s ...\r\n",
  696.             f->f_prevhost, ctime(&now));
  697.         v++;
  698.         v->iov_base = "";
  699.         v->iov_len = 0;
  700.         v++;
  701.     } else {
  702.         v->iov_base = f->f_lasttime;
  703.         v->iov_len = 15;
  704.         v++;
  705.         v->iov_base = " ";
  706.         v->iov_len = 1;
  707.         v++;
  708.     }
  709.     v->iov_base = f->f_prevhost;
  710.     v->iov_len = strlen(v->iov_base);
  711.     v++;
  712.     v->iov_base = " ";
  713.     v->iov_len = 1;
  714.     v++;
  715.  
  716.     if (msg) {
  717.         v->iov_base = msg;
  718.         v->iov_len = strlen(msg);
  719.     } else if (f->f_prevcount > 1) {
  720.         v->iov_base = repbuf;
  721.         v->iov_len = sprintf(repbuf, "last message repeated %d times",
  722.             f->f_prevcount);
  723.     } else {
  724.         v->iov_base = f->f_prevline;
  725.         v->iov_len = f->f_prevlen;
  726.     }
  727.     v++;
  728.  
  729.     dprintf("Logging to %s", TypeNames[f->f_type]);
  730.     f->f_time = now;
  731.  
  732.     switch (f->f_type) {
  733.     case F_UNUSED:
  734.         dprintf("\n");
  735.         break;
  736.  
  737.     case F_FORW:
  738.         dprintf(" %s\n", f->f_un.f_forw.f_hname);
  739.         l = sprintf(line, "<%d>%.15s %s", f->f_prevpri,
  740.             iov[0].iov_base, iov[4].iov_base);
  741.         if (l > MAXLINE)
  742.             l = MAXLINE;
  743.         if (sendto(finet, line, l, 0,
  744.             (struct sockaddr *)&f->f_un.f_forw.f_addr,
  745.             sizeof f->f_un.f_forw.f_addr) != l) {
  746.             int e = errno;
  747.             (void) close(f->f_file);
  748.             f->f_type = F_UNUSED;
  749.             errno = e;
  750.             logerror("sendto");
  751.         }
  752.         break;
  753.  
  754.     case F_CONSOLE:
  755.         if (flags & IGN_CONS) {
  756.             dprintf(" (ignored)\n");
  757.             break;
  758.         }
  759.         /* FALLTHROUGH */
  760.  
  761.     case F_TTY:
  762.     case F_FILE:
  763.         dprintf(" %s\n", f->f_un.f_fname);
  764.         if (f->f_type != F_FILE) {
  765.             v->iov_base = "\r\n";
  766.             v->iov_len = 2;
  767.         } else {
  768.             v->iov_base = "\n";
  769.             v->iov_len = 1;
  770.         }
  771.     again:
  772.         if (writev(f->f_file, iov, 6) < 0) {
  773.             int e = errno;
  774.             (void) close(f->f_file);
  775.             /*
  776.              * Check for errors on TTY's due to loss of tty
  777.              */
  778.             if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
  779.                 f->f_file = open(f->f_un.f_fname,
  780.                     O_WRONLY|O_APPEND, 0);
  781.                 if (f->f_file < 0) {
  782.                     f->f_type = F_UNUSED;
  783.                     logerror(f->f_un.f_fname);
  784.                 } else
  785.                     goto again;
  786.             } else {
  787.                 f->f_type = F_UNUSED;
  788.                 errno = e;
  789.                 logerror(f->f_un.f_fname);
  790.             }
  791.         }
  792. #ifndef linux
  793.          else if (flags & SYNC_FILE)
  794.             (void) fsync(f->f_file);
  795. #endif
  796.         break;
  797.  
  798.     case F_USERS:
  799.     case F_WALL:
  800.         dprintf("\n");
  801.         v->iov_base = "\r\n";
  802.         v->iov_len = 2;
  803.         wallmsg(f, iov);
  804.         break;
  805.     }
  806.     f->f_prevcount = 0;
  807. }
  808.  
  809. /*
  810.  *  WALLMSG -- Write a message to the world at large
  811.  *
  812.  *    Write the specified message to either the entire
  813.  *    world, or a list of approved users.
  814.  */
  815.  
  816. wallmsg(f, iov)
  817.     register struct filed *f;
  818.     struct iovec *iov;
  819. {
  820.     static int reenter;            /* avoid calling ourselves */
  821.     register FILE *uf;
  822.     register int i;
  823.     struct utmp ut;
  824.     char *p, *ttymsg();
  825.  
  826.     if (reenter++)
  827.         return;
  828.     if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
  829.         logerror(_PATH_UTMP);
  830.         reenter = 0;
  831.         return;
  832.     }
  833.     /* NOSTRICT */
  834.     while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
  835.         if (ut.ut_name[0] == '\0')
  836.             continue;
  837.         if (f->f_type == F_WALL) {
  838.             if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  839.                 errno = 0;    /* already in msg */
  840.                 logerror(p);
  841.             }
  842.             continue;
  843.         }
  844.         /* should we send the message to this user? */
  845.         for (i = 0; i < MAXUNAMES; i++) {
  846.             if (!f->f_un.f_uname[i][0])
  847.                 break;
  848.             if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
  849.                 UT_NAMESIZE)) {
  850.                 if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  851.                     errno = 0;    /* already in msg */
  852.                     logerror(p);
  853.                 }
  854.                 break;
  855.             }
  856.         }
  857.     }
  858.     (void) fclose(uf);
  859.     reenter = 0;
  860. }
  861.  
  862. #ifdef _POSIX_SOURCE
  863. void
  864. reapchild()
  865. {
  866.     int status;
  867.  
  868.     while (waitpid(0, &status, WNOHANG) > 0)
  869.         ;
  870. }
  871. #else
  872. void
  873. reapchild()
  874. {
  875.     union wait status;
  876.  
  877.     while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
  878.         ;
  879. }
  880. #endif
  881.  
  882. /*
  883.  * Return a printable representation of a host address.
  884.  */
  885. char *
  886. cvthname(f)
  887.     struct sockaddr_in *f;
  888. {
  889.     struct hostent *hp;
  890.     register char *p;
  891.     extern char *inet_ntoa();
  892.  
  893.     dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
  894.  
  895.     if (f->sin_family != AF_INET) {
  896.         dprintf("Malformed from address\n");
  897.         return ("???");
  898.     }
  899.     hp = gethostbyaddr((char *)&f->sin_addr,
  900.         sizeof(struct in_addr), f->sin_family);
  901.     if (hp == 0) {
  902.         dprintf("Host name for your address (%s) unknown\n",
  903.             inet_ntoa(f->sin_addr));
  904.         return (inet_ntoa(f->sin_addr));
  905.     }
  906.     if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
  907.         *p = '\0';
  908.     return (hp->h_name);
  909. }
  910.  
  911. void
  912. domark()
  913. {
  914.     register struct filed *f;
  915.     time_t time();
  916.  
  917.     now = time((time_t *)NULL);
  918.     MarkSeq += TIMERINTVL;
  919.     if (MarkSeq >= MarkInterval) {
  920.         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
  921.         MarkSeq = 0;
  922.     }
  923.  
  924.     for (f = Files; f; f = f->f_next) {
  925.         if (f->f_prevcount && now >= REPEATTIME(f)) {
  926.             dprintf("flush %s: repeated %d times, %d sec.\n",
  927.                 TypeNames[f->f_type], f->f_prevcount,
  928.                 repeatinterval[f->f_repeatcount]);
  929.             fprintlog(f, 0, (char *)NULL);
  930.             BACKOFF(f);
  931.         }
  932.     }
  933.     (void) alarm(TIMERINTVL);
  934. }
  935.  
  936. /*
  937.  * Print syslogd errors some place.
  938.  */
  939. logerror(type)
  940.     char *type;
  941. {
  942.     char buf[100], *strerror();
  943.  
  944.     if (errno)
  945.         (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno));
  946.     else
  947.         (void) sprintf(buf, "syslogd: %s", type);
  948.     errno = 0;
  949.     dprintf("%s\n", buf);
  950.     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
  951. }
  952.  
  953. void
  954. die(sig)
  955. {
  956.     register struct filed *f;
  957.     char buf[100];
  958.  
  959.     for (f = Files; f != NULL; f = f->f_next) {
  960.         /* flush any pending output */
  961.         if (f->f_prevcount)
  962.             fprintlog(f, 0, (char *)NULL);
  963.     }
  964.     if (sig) {
  965.         dprintf("syslogd: exiting on signal %d\n", sig);
  966.         (void) sprintf(buf, "exiting on signal %d", sig);
  967.         errno = 0;
  968.         logerror(buf);
  969.     }
  970.     (void) unlink(LogName);
  971.     exit(0);
  972. }
  973.  
  974. /*
  975.  *  INIT -- Initialize syslogd from configuration table
  976.  */
  977.  
  978. void
  979. init()
  980. {
  981.     register int i;
  982.     register FILE *cf;
  983.     register struct filed *f, *next, **nextp;
  984.     register char *p;
  985.     char cline[BUFSIZ];
  986.  
  987.     dprintf("init\n");
  988.  
  989.     /*
  990.      *  Close all open log files.
  991.      */
  992.     Initialized = 0;
  993.     for (f = Files; f != NULL; f = next) {
  994.         /* flush any pending output */
  995.         if (f->f_prevcount)
  996.             fprintlog(f, 0, (char *)NULL);
  997.  
  998.         switch (f->f_type) {
  999.           case F_FILE:
  1000.           case F_TTY:
  1001.           case F_CONSOLE:
  1002.           case F_FORW:
  1003.             (void) close(f->f_file);
  1004.             break;
  1005.         }
  1006.         next = f->f_next;
  1007.         free((char *) f);
  1008.     }
  1009.     Files = NULL;
  1010.     nextp = &Files;
  1011.  
  1012.     /* open the configuration file */
  1013.     if ((cf = fopen(ConfFile, "r")) == NULL) {
  1014.         dprintf("cannot open %s\n", ConfFile);
  1015.         *nextp = (struct filed *)calloc(1, sizeof(*f));
  1016.         cfline("*.ERR\t/dev/console", *nextp);
  1017.         (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
  1018.         cfline("*.PANIC\t*", (*nextp)->f_next);
  1019.         Initialized = 1;
  1020.         return;
  1021.     }
  1022.  
  1023.     /*
  1024.      *  Foreach line in the conf table, open that file.
  1025.      */
  1026.     f = NULL;
  1027.     while (fgets(cline, sizeof cline, cf) != NULL) {
  1028.         /*
  1029.          * check for end-of-section, comments, strip off trailing
  1030.          * spaces and newline character.
  1031.          */
  1032.         for (p = cline; isspace(*p); ++p);
  1033.         if (*p == NULL || *p == '#')
  1034.             continue;
  1035.         for (p = index(cline, '\0'); isspace(*--p););
  1036.         *++p = '\0';
  1037.         f = (struct filed *)calloc(1, sizeof(*f));
  1038.         *nextp = f;
  1039.         nextp = &f->f_next;
  1040.         cfline(cline, f);
  1041.     }
  1042.  
  1043.     /* close the configuration file */
  1044.     (void) fclose(cf);
  1045.  
  1046.     Initialized = 1;
  1047.  
  1048.     if (Debug) {
  1049.         for (f = Files; f; f = f->f_next) {
  1050.             for (i = 0; i <= LOG_NFACILITIES; i++)
  1051.                 if (f->f_pmask[i] == INTERNAL_NOPRI)
  1052.                     printf("X ");
  1053.                 else
  1054.                     printf("%d ", f->f_pmask[i]);
  1055.             printf("%s: ", TypeNames[f->f_type]);
  1056.             switch (f->f_type) {
  1057.             case F_FILE:
  1058.             case F_TTY:
  1059.             case F_CONSOLE:
  1060.                 printf("%s", f->f_un.f_fname);
  1061.                 break;
  1062.  
  1063.             case F_FORW:
  1064.                 printf("%s", f->f_un.f_forw.f_hname);
  1065.                 break;
  1066.  
  1067.             case F_USERS:
  1068.                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  1069.                     printf("%s, ", f->f_un.f_uname[i]);
  1070.                 break;
  1071.             }
  1072.             printf("\n");
  1073.         }
  1074.     }
  1075.  
  1076.     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
  1077.     dprintf("syslogd: restarted\n");
  1078. }
  1079.  
  1080. /*
  1081.  * Crack a configuration file line
  1082.  */
  1083.  
  1084. cfline(line, f)
  1085.     char *line;
  1086.     register struct filed *f;
  1087. {
  1088.     register char *p;
  1089.     register char *q;
  1090.     register int i;
  1091.     char *bp;
  1092.     int pri;
  1093.     struct hostent *hp;
  1094.     char buf[MAXLINE], ebuf[100];
  1095.  
  1096.     dprintf("cfline(%s)\n", line);
  1097.  
  1098.     errno = 0;    /* keep strerror() stuff out of logerror messages */
  1099.  
  1100.     /* clear out file entry */
  1101.     bzero((char *) f, sizeof *f);
  1102.     for (i = 0; i <= LOG_NFACILITIES; i++)
  1103.         f->f_pmask[i] = INTERNAL_NOPRI;
  1104.  
  1105.     /* scan through the list of selectors */
  1106.     for (p = line; *p && *p != '\t';) {
  1107.  
  1108.         /* find the end of this facility name list */
  1109.         for (q = p; *q && *q != '\t' && *q++ != '.'; )
  1110.             continue;
  1111.  
  1112.         /* collect priority name */
  1113.         for (bp = buf; *q && !index("\t,;", *q); )
  1114.             *bp++ = *q++;
  1115.         *bp = '\0';
  1116.  
  1117.         /* skip cruft */
  1118.         while (index(", ;", *q))
  1119.             q++;
  1120.  
  1121.         /* decode priority name */
  1122.         if (*buf == '*')
  1123.             pri = LOG_PRIMASK + 1;
  1124.         else {
  1125.             pri = decode(buf, prioritynames);
  1126.             if (pri < 0) {
  1127.                 (void) sprintf(ebuf,
  1128.                     "unknown priority name \"%s\"", buf);
  1129.                 logerror(ebuf);
  1130.                 return;
  1131.             }
  1132.         }
  1133.  
  1134.         /* scan facilities */
  1135.         while (*p && !index("\t.;", *p)) {
  1136.             for (bp = buf; *p && !index("\t,;.", *p); )
  1137.                 *bp++ = *p++;
  1138.             *bp = '\0';
  1139.             if (*buf == '*')
  1140.                 for (i = 0; i < LOG_NFACILITIES; i++)
  1141.                     f->f_pmask[i] = pri;
  1142.             else {
  1143.                 i = decode(buf, facilitynames);
  1144.                 if (i < 0) {
  1145.                     (void) sprintf(ebuf,
  1146.                         "unknown facility name \"%s\"",
  1147.                         buf);
  1148.                     logerror(ebuf);
  1149.                     return;
  1150.                 }
  1151.                 f->f_pmask[i >> 3] = pri;
  1152.             }
  1153.             while (*p == ',' || *p == ' ')
  1154.                 p++;
  1155.         }
  1156.  
  1157.         p = q;
  1158.     }
  1159.  
  1160.     /* skip to action part */
  1161.     while (*p == '\t')
  1162.         p++;
  1163.  
  1164.     switch (*p)
  1165.     {
  1166.     case '@@':
  1167.         if (!InetInuse)
  1168.             break;
  1169.         (void) strcpy(f->f_un.f_forw.f_hname, ++p);
  1170.         hp = gethostbyname(p);
  1171.         if (hp == NULL) {
  1172.             extern int h_errno, h_nerr;
  1173.             extern char **h_errlist;
  1174.  
  1175.             logerror((u_int)h_errno < h_nerr ?
  1176.                 h_errlist[h_errno] : "Unknown error");
  1177.             break;
  1178.         }
  1179.         bzero((char *) &f->f_un.f_forw.f_addr,
  1180.              sizeof f->f_un.f_forw.f_addr);
  1181.         f->f_un.f_forw.f_addr.sin_family = AF_INET;
  1182.         f->f_un.f_forw.f_addr.sin_port = LogPort;
  1183.         bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
  1184.         f->f_type = F_FORW;
  1185.         break;
  1186.  
  1187.     case '/':
  1188.         (void) strcpy(f->f_un.f_fname, p);
  1189.         if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
  1190.             f->f_file = F_UNUSED;
  1191.             logerror(p);
  1192.             break;
  1193.         }
  1194.         if (isatty(f->f_file))
  1195.             f->f_type = F_TTY;
  1196.         else
  1197.             f->f_type = F_FILE;
  1198.         if (strcmp(p, ctty) == 0)
  1199.             f->f_type = F_CONSOLE;
  1200.         break;
  1201.  
  1202.     case '*':
  1203.         f->f_type = F_WALL;
  1204.         break;
  1205.  
  1206.     default:
  1207.         for (i = 0; i < MAXUNAMES && *p; i++) {
  1208.             for (q = p; *q && *q != ','; )
  1209.                 q++;
  1210.             (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
  1211.             if ((q - p) > UT_NAMESIZE)
  1212.                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
  1213.             else
  1214.                 f->f_un.f_uname[i][q - p] = '\0';
  1215.             while (*q == ',' || *q == ' ')
  1216.                 q++;
  1217.             p = q;
  1218.         }
  1219.         f->f_type = F_USERS;
  1220.         break;
  1221.     }
  1222. }
  1223.  
  1224.  
  1225. /*
  1226.  *  Decode a symbolic name to a numeric value
  1227.  */
  1228.  
  1229. decode(name, codetab)
  1230.     char *name;
  1231.     CODE *codetab;
  1232. {
  1233.     register CODE *c;
  1234.     register char *p;
  1235.     char buf[40];
  1236.  
  1237.     if (isdigit(*name))
  1238.         return (atoi(name));
  1239.  
  1240.     (void) strcpy(buf, name);
  1241.     for (p = buf; *p; p++)
  1242.         if (isupper(*p))
  1243.             *p = tolower(*p);
  1244.     for (c = codetab; c->c_name; c++)
  1245.         if (!strcmp(buf, c->c_name))
  1246.             return (c->c_val);
  1247.  
  1248.     return (-1);
  1249. }
  1250. @
  1251.  
  1252.  
  1253. 1.1
  1254. log
  1255. @Initial revision
  1256. @
  1257. text
  1258. @d79 3
  1259. a81 1
  1260. #include <sys/msgbuf.h>
  1261. d86 5
  1262. a90 1
  1263. #include <sys/signal.h>
  1264. d103 4
  1265. d207 4
  1266. a210 1
  1267.     struct sockaddr_un sunx, fromunix;
  1268. d214 1
  1269. a214 1
  1270.     char line[MSG_BSIZE + 1];
  1271. d218 3
  1272. d257 14
  1273. d276 1
  1274. d280 10
  1275. d294 11
  1276. a304 3
  1277.     if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
  1278.         sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+
  1279.         strlen(sunx.sun_path)) < 0 ||
  1280. d310 1
  1281. a310 1
  1282.     }
  1283. d350 4
  1284. d355 1
  1285. d384 3
  1286. d390 1
  1287. d394 7
  1288. a400 2
  1289.             } else if (i < 0 && errno != EINTR)
  1290.                 logerror("recvfrom unix");
  1291. d529 6
  1292. a534 1
  1293.     int omask, msglen;
  1294. d541 6
  1295. d548 1
  1296. d583 3
  1297. d587 1
  1298. d644 3
  1299. d648 1
  1300. d761 3
  1301. a763 1
  1302.         } else if (flags & SYNC_FILE)
  1303. d765 1
  1304. d832 10
  1305. d850 1
  1306. @
  1307.